package com.game.core.db.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.game.core.util.TimeUtils;

/**
 * Created by  on 2017/2/28.
 */
public class ObjectUtils {

	/**
	 * 获取某个对象某些字段的Map
	 * 
	 * @param obj
	 */
	final static Logger logger = LoggerFactory.getLogger(ObjectUtils.class);

	public static Map<String, String> getMap(Object obj, String... strings) {
		Map<String, String> map = new HashMap<String, String>();
		boolean addAllFields = false;
		if (strings == null || strings.length == 0) {
			addAllFields = true;
		}
		if (obj != null) {
			Field[] fields = getAllFields(obj);
			for (Field field : fields) {
				field.setAccessible(true);
				try {
					boolean needsAddToMap = false;
					for (String s : strings) {
						if (field.getName().equals(s)) {
							needsAddToMap = true;
							break;
						}
					}
					if (needsAddToMap || addAllFields) {
						map.put(field.getName(), getFieldsValueStr(obj, field.getName()).toString());
					}
				} catch (Exception e) {
					//e.printStackTrace();
					logger.error("ObjectUtils Failed to getMap Exception err={}", e.toString());
				}
			}
		}
		if (!addAllFields && strings.length != map.size()) {
			return new HashMap<String, String>();
		}
		return map;
	}

	private static Field[] getAllFields(Object obj) {
		Class<?> clazz = obj.getClass();
		Field[] rt = null;
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			Field[] tmp = clazz.getDeclaredFields();
			rt = combine(rt, tmp);
		}
		return rt;
	}

	private static Field[] combine(Field[] a, Field[] b) {
		if (a == null) {
			return b;
		}
		if (b == null) {
			return a;
		}
		Field[] rt = new Field[a.length + b.length];
		System.arraycopy(a, 0, rt, 0, a.length);
		System.arraycopy(b, 0, rt, a.length, b.length);
		return rt;
	}

	public static Object getFieldsValueObj(Object obj, String fieldName) {
		Object value = null;
		Field field = getDeclaredField(obj, fieldName);
		if (field == null) {
			return value;
		}
		field.setAccessible(true);
		try {
			value = field.get(obj);
		} catch (Exception e) {
			logger.error("ObjectUtils Failed to getFieldsValueObj Exception err={}", e.toString());
		}
		return value;
	}

	public static String getFieldsValueStr(Object obj, String fieldName) {
		Object o = ObjectUtils.getFieldsValueObj(obj, fieldName);
		return getObjectString(o);
	}

	public static String getObjectString(Object object) {
		// 如果为空则输出为""
		if (object == null) {
			return "";
		}
		if (object instanceof Date) {
			return TimeUtils.dateToString((Date) object);
		}
		if(object instanceof Map){
			return JSON.toJSONString(object);
		}
		if(object instanceof HashMap){
			return JSON.toJSONString(object);
		}
		if(object instanceof List){
			return JSON.toJSONString(object);
		}
		if(object instanceof ArrayList){
			return JSON.toJSONString(object);
		}
		return object.toString();
	}

	public static Map<String, String> getTransferMap(Map<String, Object> map) {
		Map<String, String> transferMap = new HashMap<>();
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			transferMap.put(entry.getKey(), getObjectString(entry.getValue()));
		}
		return transferMap;
	}

	public static String getFieldsValueStr(Object obj, String[] fieldName) {
		Map<String, String> keyMap = ObjectUtils.getMap(obj, fieldName);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < fieldName.length; i++) {
			String keyName = fieldName[i];
			sb.append(keyMap.get(keyName));
			if (i == fieldName.length - 1) {
				break;
			}
			sb.append("#");
		}
		return sb.toString();
	}

	private static Field getDeclaredField(Object object, String fieldName) {
		Field field = null;
		Class<?> clazz = object.getClass();
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				field = clazz.getDeclaredField(fieldName);
				if (field!=null) break;
			} catch (NoSuchFieldException e) {
				continue;
			} catch (SecurityException e) {
				logger.error("ObjectUtils Failed to getDeclaredField Exception err={}", e.toString());
				continue;
			} catch (NullPointerException e) {
				logger.error("ObjectUtils Failed to getDeclaredField Exception err={}", e.toString());
				break;
			}
		}
		return field;
	}

	private static Method getSetMethod(Object object, String methodName, Class<?> fieldType) {
		Method method = null;
		Class<?> clazz = object.getClass();
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				method = clazz.getDeclaredMethod(methodName, fieldType);
				if (method!=null) break;
			} catch (NoSuchMethodException e) {
				continue;
			} catch (SecurityException e) {
				logger.error("ObjectUtils Failed to getSetMethod Exception err={}", e.toString());
				continue;
			} catch (NullPointerException e) {
				logger.error("ObjectUtils Failed to getSetMethod Exception err={}", e.toString());
				break;
			}
		}
		return method;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getObjFromMap(Map<String, String> map, Object obj) {
		try {
			for (String key : map.keySet()) {
				if (key == null || key.isEmpty()) {
					continue;
				}
				String value = map.get(key);
				// 如果为空放弃，默认设置为空
				if (StringUtils.isEmpty(value)) {
					continue;
				}
				Field field = getDeclaredField(obj, key);
				if (field == null) {
					continue;
				}
				String mathodname = buildSetMethod(key);
				if (mathodname == "set") {
					continue;
				}
				Method method = getSetMethod(obj, mathodname, field.getType());
				if (method == null) {
					continue;
				}
				if (field.getType() == Integer.class || field.getType() == int.class) {
					method.invoke(obj, Integer.parseInt(map.get(key)));
				} else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
					method.invoke(obj, Boolean.parseBoolean(map.get(key)));
				} else if (field.getType() == Long.class || field.getType() == long.class) {
					method.invoke(obj, Long.parseLong(map.get(key)));
				} else if (field.getType() == Float.class || field.getType() == float.class) {
					method.invoke(obj, Float.parseFloat(map.get(key)));
				} else if (field.getType() == Double.class || field.getType() == double.class) {
					method.invoke(obj, Double.parseDouble(map.get(key)));
				} else if (field.getType() == Byte.class || field.getType() == byte.class) {
					method.invoke(obj, Byte.parseByte(map.get(key)));
				} else if (field.getType() == Short.class || field.getType() == short.class) {
					method.invoke(obj, Short.parseShort(map.get(key)));
				} else if (field.getType() == String.class) {
					method.invoke(obj, map.get(key));
				} else if (field.getType() == Date.class) {
					method.invoke(obj, TimeUtils.stringToDate(map.get(key)));
				} else if (field.getType() == Timestamp.class) {
					method.invoke(obj, TimeUtils.stringtoTimestamp(map.get(key)));
				}else if((field.getType() == Map.class)||(field.getType() == HashMap.class)) {
					Map<String, String> mapFields = JSON.parseObject(map.get(key).replaceAll("=", ":"), HashMap.class);
					if(mapFields.size()>0) {
						method.invoke(obj, mapFields);
					}
				}else if((field.getType() == List.class) || (field.getType() == ArrayList.class)) {
					List<Object> listFields = JSON.parseObject(map.get(key).replaceAll("=", ":"), ArrayList.class);
					if(listFields.size()>0) {
						method.invoke(obj, listFields);
					}
				}
			}
			return (T) obj;
		} catch (Exception e) {
			// e.printStackTrace();
			logger.error("ObjectUtils Failed to getObjFromMap Exception err={}", e.toString());
		}
		return null;
	}

	/**
	 * 从map里构造出一个实例对象
	 * 
	 * @param map
	 * @param clazz
	 * @return
	 */
	public static <T> T getObjFromMap(Map<String, String> map, Class<?> clazz) {
		try {
			Object obj = clazz.newInstance();
			return getObjFromMap(map, obj);
		} catch (Exception e) {
			// e.printStackTrace();
			logger.error("ObjectUtils Failed to getObjFromMap Exception err={}", e.toString());
		}
		return null;
	}

	private static String buildSetMethod(String fieldName) {
		StringBuffer sb = new StringBuffer("set");
		if (fieldName.length() > 1) {
			String first = fieldName.substring(0, 1);
			String next = fieldName.substring(1);
			sb.append(first.toUpperCase()).append(next);
		} else if (fieldName.length() == 1) {
			sb.append(fieldName.toUpperCase());
		}
		return sb.toString();
	}

	/**
	 * 判断某个list是否没有数据
	 * 
	 * @param <T>
	 * @param list
	 * @return
	 */
	public static <T> boolean isEmpityList(List<T> list) {
		boolean b = false;
		if (list == null || list.isEmpty()) {
			b = true;
		}
		return b;
	}

}
